package com.itmuch.providerdemo.feign;

import feign.*;
import feign.codec.ErrorDecoder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.TimeUnit;

// 整合了ribbon的client
@FeignClient(name = "provider-demo", configuration = T.class)
public interface ProviderDemoFeignClient {
    /**
     * 当调用hello()的时候，会自动拼接http://provider-demo/hello调用
     * 并把响应反序列化成String对象
     * [无需扩展] Decoder: 当拿到响应之后，响应是个json，由decoder反序列化成接口的返回类型
     * [无需扩展] Encoder: 在请求的时候，如果有requestbody，会把这个对象序列化之后，再去请求
     * Logger: 日志
     * [无需扩展] Contract: feign的注解支持 SpringMvcContract
     * Feign.builder:  feign的入口, 可能会扩展
     * Client: feign的传输层
     * <p>
     * 和spring mvc的用法差异
     * 1. 上传文件，spring mvc: @RequestPart，@RequestParam | feign: @RequestPart
     * 2. 当用GET请求传输，并且有多个参数的时候，有所不同
     */
    @GetMapping("hello")
    String hello(@RequestParam("name") String name);

    @GetMapping("/haha")
    User haha();
}

@Data
class User {
    private String name;
}

@Slf4j
class T {
    @Bean
    Logger.Level level() {
        return Logger.Level.FULL;
    }

    @Bean
    public RequestInterceptor requestInterceptor() {
        return template -> {
            // 利用spring mvc的静态方法拿request的技巧
            RequestAttributes ra = RequestContextHolder.getRequestAttributes();
            ServletRequestAttributes sra = (ServletRequestAttributes) ra;
            HttpServletRequest request = sra.getRequest();

            template.query("haha", request.getParameter("xx"));
            template.header("X-Token", request.getHeader("C-Token"));
        };
    }

    @Bean
    public Request.Options v() {
        return new Request.Options(10L, TimeUnit.SECONDS, 10L, TimeUnit.SECONDS, false);
    }

    @Bean
    public ErrorDecoder decoder() {
        return new ErrorDecoder() {
            @Override
            public Exception decode(String methodKey, Response response) {
                Response.Body body = response.body();
                try {
                    InputStream inputStream = body.asInputStream();
                    String s = IOUtils.toString(inputStream);
                    log.error("methodKey= {}, response = {}", methodKey, s);
                    return new FeignRemoteException("hahaha");
                } catch (IOException e) {
                    return new FeignRemoteException(e.getMessage());
                }
            }
        };
    }
}
